#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
from functools import partial
import requests

__author__ = "raptor"

logger = logging.getLogger(__name__)


class APIError(Exception):
    pass


class AppServerApi(object):
    SSL_VERIFY = False
    API_URL = ""
    HOSPITAL = ""

    def __init__(self):
        pass

    # url中不带参数的可以自动生成处理方法
    # 类似： GET_xxxx_yyyy 可以自动转为
    # GET API_ROOT/xxxx/yyyy
    # url中带参数的自动生成方法是：
    # POST_xxxx_ID_yyyy_ID
    # 转为： POST "API_ROOT/xxxx/%s/yyyy/%s" % args
    def __getattr__(self, name):
        name = name.replace("__", "%-%")
        funcs = name.split("_")
        funcs = [f.replace("%-%", "_") for f in funcs]
        if funcs[0] in ['GET', 'POST', 'PUT', 'DELETE']:
            method = funcs[0]
            funcs = [part if part != "ID" else "%s" for part in funcs]
            func = "/".join(funcs[1:])
            fn = partial(self._generic_call, method, func)
            setattr(self, name, fn)
            return fn
        else:
            raise AttributeError('Invalid function name!')

    def _generic_call(self, method, func, *args, **kwargs):
        url = AppServerApi.API_URL
        if func:
            func = func % args  # 参数数量不匹配会导致 TypeError
            url = "/".join([url, func])
            headers = {}
        logger.warning("request url: %s, headers: %s, kwargs: %s", str(url), str(headers), str(kwargs))
        r = self._process(method, url, kwargs, headers, AppServerApi.SSL_VERIFY)
        try:
            r.raise_for_status()
            status = 200
            if r.status_code == 200:
                result = r.json()
                logger.warning("request url: %s", str(result))
                if len(result) == 0:
                    status = 400
                    result = "没有数据"
                elif len(result) > 0 and "Error" in result[0] and result[0]["Error"] != "":
                    status = 400
                    result = result[0]["Error"]
                # if result["Error"]:
                #     status = 400
                #     result = result["Error"]
            else:
                status = r.status_code
            return status, result
        except Exception as e:
            from traceback import format_exc
            logger.error(format_exc())
            return 501, "未知错误:{error}".format(error="参数有误")

    def _process(self, method, url, params, headers, ssl_verify):
        fn = getattr(requests, method.lower())
        if fn:
            if method in ['GET', 'DELETE']:
                r = fn(url, params=params)
                # r = fn(url, params=params, headers=headers, verify=ssl_verify)
            else:
                r = fn(url, data=params, headers=headers)
                # r = fn(url, data=params, headers=headers, verify=ssl_verify)
        else:
            raise AttributeError("Invalid http method name!")
        return r


class APIReservation(object):
    SSL_VERIFY = False
    API_URL = ""

    def __init__(self):
        pass

    # url中不带参数的可以自动生成处理方法
    # 类似： GET_xxxx_yyyy 可以自动转为
    # GET API_ROOT/xxxx/yyyy
    # url中带参数的自动生成方法是：
    # POST_xxxx_ID_yyyy_ID
    # 转为： POST "API_ROOT/xxxx/%s/yyyy/%s" % args
    def __getattr__(self, name):
        name = name.replace("__", "%-%")
        funcs = name.split("_")
        funcs = [f.replace("%-%", "_") for f in funcs]
        if funcs[0] in ['GET', 'POST', 'PUT', 'DELETE', 'GETPOST']:
            method = funcs[0]
            funcs = [part if part != "ID" else "%s" for part in funcs]
            func = "/".join(funcs[1:])
            fn = partial(self._generic_call, method, func)
            setattr(self, name, fn)
            return fn
        else:
            raise AttributeError('Invalid function name!')

    def _generic_call(self, method, func, *args, **kwargs):
        url = APIReservation.API_URL
        if func:
            func = func % args  # 参数数量不匹配会导致 TypeError
            url = "/".join([url, func])
            headers = {}
            #
        if method == "GETPOST":
            from urllib.parse import urlencode
            method = "POST"
            url = '?'.join([url, urlencode(kwargs)])
        logger.warning("request url: %s, headers: %s, kwargs: %s", str(url), str(headers), str(kwargs))
        r = self._process(method, url, kwargs, headers, AppServerApi.SSL_VERIFY)
        try:
            r.raise_for_status()
            status = 200
            if r.status_code == 200:
                result = r.json()
                logger.warning("result: %s", str(result))
                if result["flag"]["status"] == False:
                    status = 400
                    result = result["flag"]["message"]
            else:
                status = r.status_code
            return status, result
        except Exception as e:
            from traceback import format_exc
            logger.error(format_exc())
            return 501, "未知错误:{error}".format(error="参数有误")

    def _process(self, method, url, params, headers, ssl_verify):
        fn = getattr(requests, method.lower())
        if fn:
            if method in ['GET', 'DELETE']:
                r = fn(url, params=params)
                # r = fn(url, params=params, headers=headers, verify=ssl_verify)
            else:
                r = fn(url, data=params, headers=headers)
                # r = fn(url, data=params, headers=headers, verify=ssl_verify)
        else:
            raise AttributeError("Invalid http method name!")
        return r


class APIBase(object):
    SSL_VERIFY = False
    API_URL = ""

    def __init__(self):
        self.url = self.API_URL

    def __getattr__(self, name):
        if name in ['get', 'post', 'put', 'delete']:
            fn = partial(self._generic_call, name)
            setattr(self, name, fn)
            return fn
        else:
            raise AttributeError("Invalid method name!")

    def _generic_call(self, method, **kwargs):
        url = self.url
        logger.debug("kwargs: %s" % str(kwargs))
        fn = getattr(requests, method)
        if method in ['get', 'delete']:
            r = fn(url, params=kwargs, verify=self.SSL_VERIFY)
        else:
            r = fn(url, data=kwargs, verify=self.SSL_VERIFY)
        try:
            r.raise_for_status()
            status = 200
            if r.status_code == 200:
                result = r.json()
                if "error" in result and result["error"]:
                    status = 400
                    result = result["error"]
                    self.access_token = None
            else:
                status = r.status_code
            return status, result
        except requests.exceptions.HTTPError as e:
            # from traceback import format_exc
            # logger.error(format_exc())
            try:
                result = r.text
                return r.status_code, result.get("message", "未知错误:{error}".format(error=str(result)))
                # raise APIError(result.get("message", "未知错误"))
            except ValueError:
                return r.status_code, "未知错误:{error}".format(error=r.text)


class APIBase1(object):
    SSL_VERIFY = False
    API_URL = ""

    def __init__(self):
        pass

    def __getattr__(self, name):
        if name in ['get', 'post', 'put', 'delete']:
            fn = partial(self._generic_call, name)
            setattr(self, name, fn)
            return fn
        else:
            raise AttributeError("Invalid method name!")

    def _generic_call(self, method, path, params, **kwargs):
        url = "".join([self.API_URL, path])
        logger.debug("kwargs: %s" % str(params))
        fn = getattr(requests, method)
        headers = kwargs["headers"] if kwargs["headers"] else {"Content-Type": "application/json"}
        if method in ['get', 'delete']:
            r = fn(url, params=params, headers=headers)
        else:
            r = fn(url, data=params, headers=headers)
        try:
            r.raise_for_status()
            return r.json()
        except requests.exceptions.HTTPError as e:
            # from traceback import format_exc
            # logger.error(format_exc())
            try:
                result = r.text
                return r.status_code, result.get("message", "未知错误:{error}".format(error=str(result)))
                # raise APIError(result.get("message", "未知错误"))
            except ValueError:
                return r.status_code, "未知错误:{error}".format(error=r.text)
